﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YueRu.Common.Validation
{
    public class ModelValidationError
    {
        public string FieldName { get; set; }
        public string Message { get; set; }
    }

    public static class DataAnnotationHelper
    {
        public static List<ModelValidationError> IsValid<T>(this T o, bool only1Level = false)
        {
            return IsValid(typeof (T), o, only1Level);
        }

        private static List<ModelValidationError> IsValid(Type t, object o, bool only1Level)
        {
            var errors = new List<ModelValidationError>();

            var descriptor = GetTypeDescriptor(t);

            foreach (PropertyDescriptor propertyDescriptor in descriptor.GetProperties())
            {
                foreach (var validationAttribute in propertyDescriptor.Attributes.OfType<ValidationAttribute>())
                {
                    if (validationAttribute.IsValid(propertyDescriptor.GetValue(o))) continue;
                    var error = new ModelValidationError
                    {
                        FieldName = propertyDescriptor.Name,
                        Message = validationAttribute.FormatErrorMessage(propertyDescriptor.Name)
                    };
                    errors.Add(error);
                }
            }
            if (!only1Level)
            {
                if (o.GetType().IsClass && !(o is string) && !(o is Array))
                {
                    foreach (var p in o.GetType().GetProperties())
                    {
                        object pValue = p.GetValue(o, null);
                        if (pValue != null)
                        {
                            List<ModelValidationError> pErrors = IsValid(p.PropertyType, pValue, only1Level);
                            errors.AddRange(pErrors);
                        }
                    }
                }
            }


            return errors;
        }

        private static ICustomTypeDescriptor GetTypeDescriptor(Type type)
        {
            return new AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type);
        }

        public static string ErrorsToStr(List<ModelValidationError> list)
        {
            var sb = new StringBuilder();
            foreach (var error in list)
            {
                sb.AppendFormat("FileName:{0},Message:{1};", error.FieldName, error.Message);
            }
            return sb.ToString();
        }
    }
}